using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using DevExpress.Data.Filtering;
using DevExpress.Xpo;
using SmartPeople.Framework.SecuritySpace;
using SmartPeople.Framework.SecuritySpace;

namespace SmartPeople.Framework.Security.Providers.XPO
{
    /// <summary>
    /// 
    /// </summary>
    internal class XPSecurityRoleProvider : ISecurityRoleProvider
    {
        private Guid applicationID;
        private ISecurityUsersProvider securityUserProvider;

        public XPSecurityRoleProvider(Guid applicationID, ISecurityUsersProvider securityUserProvider)
        {
            this.applicationID = applicationID;
            this.securityUserProvider = securityUserProvider;
        }


        /// <summary>
        /// Gets the count.
        /// </summary>
        /// <value>The count.</value>
        public int Count
        {
            get
            {
                GroupOperator criteria = new GroupOperator();
                criteria.Operands.Add(
                    new BinaryOperator("SecurityApplicationID", applicationID, BinaryOperatorType.Equal));
                XPCollection<XPSecurityRole> xpCollection = new XPCollection<XPSecurityRole>(criteria);
                return xpCollection.Count;
            }
        }

        #region CreateRole

        /// <summary>
        /// Creates the role.
        /// </summary>
        /// <param name="roleName">Name of the role.</param>
        /// <returns></returns>
        public ISecurityRole CreateRole(string roleName)
        {
            XPSecurityRole securityRole = new XPSecurityRole();
            securityRole.SecurityApplicationID = applicationID;
            securityRole.Name = roleName;
            securityRole.CreationDate = DateTime.Now;
            securityRole.Save();
            return securityRole;
        }

        #endregion

        #region CreateRole

        /// <summary>
        /// Creates the role.
        /// </summary>
        /// <param name="roleName">Name of the role.</param>
        /// <param name="description">The description.</param>
        /// <param name="comment">The comment.</param>
        /// <returns></returns>
        public ISecurityRole CreateRole(string roleName, string description, string comment)
        {
            XPSecurityRole securityRole = new XPSecurityRole();
            securityRole.SecurityApplicationID = applicationID;
            securityRole.Name = roleName;
            securityRole.Description = description;
            securityRole.Comment = comment;
            securityRole.CreationDate = DateTime.Now;
            securityRole.Save();
            return securityRole;
        }

        /// <summary>
        /// Creates the role.
        /// </summary>
        /// <param name="roleGuid">The role GUID.</param>
        /// <returns></returns>
        public ISecurityRole CreateRole(Guid roleGuid)
        {
            XPSecurityRole securityRole = new XPSecurityRole();
            securityRole.SecurityApplicationID = applicationID;
            securityRole.GID = roleGuid;
            securityRole.CreationDate = DateTime.Now;
            securityRole.Save();
            return securityRole;
        }

        #endregion

        #region GetAllRoles

        /// <summary>
        /// Gets all roles.
        /// </summary>
        /// <returns></returns>
        public ISecurityRole[] GetAllRoles()
        {
            XPCollection<XPSecurityRole> xpCollection = new XPCollection<XPSecurityRole>();
            ISecurityRole[] securityRoles = new ISecurityRole[xpCollection.Count];
            int length = securityRoles.Length;
            while (length > 0)
            {
                securityRoles[securityRoles.Length - length] = xpCollection[securityRoles.Length - length];
                length--;
            }
            return securityRoles;
        }

        #endregion

        #region GetRole

        /// <summary>
        /// Gets the role.
        /// </summary>
        /// <param name="roleName">Name of the role.</param>
        /// <returns></returns>
        public ISecurityRole GetRole(string roleName)
        {
            GroupOperator criteria = new GroupOperator();
            criteria.Operands.Add(new BinaryOperator("Name", roleName, BinaryOperatorType.Equal));
            //without adding application id how will you know which role belongs to which application id
            criteria.Operands.Add(new BinaryOperator("SecurityApplicationID", applicationID, BinaryOperatorType.Equal));
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityRole), criteria);
            //xpCollection.Reload();
            if (xpCollection.Count == 1)
            {
                XPSecurityRole securityRole = (XPSecurityRole) xpCollection[0];
                return securityRole;
            }
            return null;
        }

        #endregion

        #region UpdateRole

        /// <summary>
        /// Updates the role.
        /// </summary>
        /// <param name="role">The role.</param>
        public void UpdateRole(ISecurityRole role)
        {
            XPSecurityRole securityRole = (XPSecurityRole) role;
            if (securityRole != null)
                securityRole.Save();
            else
                throw new ArrayTypeMismatchException("Argument should be type of XPSecurityRole!");
        }

        #endregion

        #region RoleExists

        /// <summary>
        /// Roles the exists.
        /// </summary>
        /// <param name="roleName">Name of the role.</param>
        /// <returns></returns>
        public bool RoleExists(string roleName)
        {
            ISecurityRole securityRole = GetRole(roleName);
            return (securityRole != null);
        }

        /// <summary>
        /// Roles the exists.
        /// </summary>
        /// <param name="roleGuid">The role GUID.</param>
        /// <returns></returns>
        public bool RoleExists(Guid roleGuid)
        {
            ISecurityRole securityRole = GetRole(roleGuid);
            return (securityRole != null);
        }

        #endregion

        #region DeleteRole

        /// <summary>
        /// Deletes the role.
        /// </summary>
        /// <param name="roleName">Name of the role.</param>
        /// <returns></returns>
        public bool DeleteRole(string roleName)
        {
            return DeleteRole(roleName, false);
        }

        #endregion

        #region DeleteRole

        /// <summary>
        /// Deletes the role.
        /// </summary>
        /// <param name="roleName">Name of the role.</param>
        /// <param name="throwOnPopulatedRole">if set to <c>true</c> [throw on populated role].</param>
        /// <returns></returns>
        public bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            XPSecurityRole securityRole = (XPSecurityRole) GetRole(roleName);
            if (securityRole == null)
                return false;
            else
            {
                securityRole.Delete();
                securityRole.Session.PurgeDeletedObjects();
                return true;
            }
        }

        #endregion

        #region GetRoles

        /// <summary>
        /// Gets the roles.
        /// </summary>
        /// <param name="roleNames">The role names.</param>
        /// <returns></returns>
        public ISecurityRole[] GetRoles(string[] roleNames)
        {
            List<ISecurityRole> securityRoles = new List<ISecurityRole>();
            foreach (string roleName in roleNames)
            {
                ISecurityRole securityRole = GetRole(roleName);
                if (securityRole != null)
                    securityRoles.Add(securityRole);
            }
            return securityRoles.ToArray();
        }

        /// <summary>
        /// Gets the role.
        /// </summary>
        /// <param name="roleguid">The roleguid.</param>
        /// <returns></returns>
        public ISecurityRole GetRole(Guid roleguid)
        {
            GroupOperator criteria = new GroupOperator();
            criteria.Operands.Add(new BinaryOperator("GID", roleguid, BinaryOperatorType.Equal));
            XPCollection xpCollection = new XPCollection(typeof (XPSecurityRole), criteria);
            //xpCollection.Reload();
            if (xpCollection.Count == 1)
            {
                XPSecurityRole securityRole = (XPSecurityRole) xpCollection[0];
                return securityRole;
            }
            return null;
        }

        #endregion

        #region AddUsersToRoles

        /// <summary>
        /// Adds the users to roles.
        /// </summary>
        /// <param name="usernames">The usernames.</param>
        /// <param name="roleNames">The role names.</param>
        public void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            ISecurityRole[] securityRoles = GetRoles(roleNames);
            ISecurityUser[] securityUsers = securityUserProvider.GetUsers(usernames);

            foreach (ISecurityRole securityRole in securityRoles)
            {
                XPSecurityRole xpSecurityRole = (XPSecurityRole) securityRole;
                if (xpSecurityRole != null)
                {
                    foreach (ISecurityUser securityUser in securityUsers)
                    {
                        XPSecurityUser xpSecurityUser = (XPSecurityUser) securityUser;
                        if (xpSecurityUser != null)
                        {
                            xpSecurityRole.Users.Add(xpSecurityUser);
                        }
                    }
                    xpSecurityRole.Save();
                }
            }
        }

        #endregion

        #region RemoveUsersFromRoles

        /// <summary>
        /// Removes the users from roles.
        /// </summary>
        /// <param name="userNames">The user names.</param>
        /// <param name="roleNames">The role names.</param>
        public void RemoveUsersFromRoles(string[] userNames, string[] roleNames)
        {
            ISecurityRole[] securityRoles = GetRoles(roleNames);
            ISecurityUser[] securityUsers = securityUserProvider.GetUsers(userNames);

            foreach (ISecurityRole securityRole in securityRoles)
            {
                XPSecurityRole xpSecurityRole = (XPSecurityRole) securityRole;
                if (xpSecurityRole != null)
                {
                    foreach (ISecurityUser securityUser in securityUsers)
                    {
                        XPSecurityUser xpSecurityUser = (XPSecurityUser) securityUser;
                        if (xpSecurityUser != null)
                        {
                            xpSecurityRole.Users.Remove(xpSecurityUser);
                        }
                    }
                    xpSecurityRole.Save();
                    xpSecurityRole.Session.PurgeDeletedObjects();
                }
            }
        }

        #endregion

        #region GetRolesForUser

        /// <summary>
        /// Gets the roles for user.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public string[] GetRolesForUser(string userName)
        {
            StringCollection roleNamesCollection = new StringCollection();

            XPSecurityUser securityUser = (XPSecurityUser) securityUserProvider.GetUser(userName, false);
            if (securityUser != null)
            {
                XPCollection<XPSecurityRole> securityRoles =
                    new XPCollection<XPSecurityRole>(
                        new ContainsOperator("Users", new BinaryOperator("This", securityUser)));
                foreach (XPSecurityRole securityRole in securityRoles)
                {
                    roleNamesCollection.Add(securityRole.Name);
                }
            }

            string[] usersInRole = new string[roleNamesCollection.Count];
            roleNamesCollection.CopyTo(usersInRole, 0);
            return usersInRole;
        }

        /// <summary>
        /// Gets the roles for user.
        /// </summary>
        /// <param name="userToken">The user token.</param>
        /// <returns></returns>
        public string[] GetRolesForUser(IToken userToken)
        {
            StringCollection roleNamesCollection = new StringCollection();
            XPSecurityUser securityUser = (XPSecurityUser) securityUserProvider.GetUser(userToken, false);
            if (securityUser != null)
            {
                XPCollection<XPSecurityRole> securityRoles =
                    new XPCollection<XPSecurityRole>(
                        new ContainsOperator("Users", new BinaryOperator("This", securityUser)));
                foreach (XPSecurityRole securityRole in securityRoles)
                {
                    roleNamesCollection.Add(securityRole.Name);
                }
            }

            string[] usersInRole = new string[roleNamesCollection.Count];
            roleNamesCollection.CopyTo(usersInRole, 0);
            return usersInRole;
        }

        #endregion

        #region GetUsersInRole

        /// <summary>
        /// Gets the users in role.
        /// </summary>
        /// <param name="roleName">Name of the role.</param>
        /// <returns></returns>
        public string[] GetUsersInRole(string roleName)
        {
            StringCollection userNamesCollection = new StringCollection();

            XPSecurityRole securityRole = (XPSecurityRole) GetRole(roleName);
            if (securityRole != null)
            {
                foreach (XPSecurityUser securityUser in securityRole.Users)
                {
                    userNamesCollection.Add(securityUser.UserName);
                }
            }

            string[] usersInRole = new string[userNamesCollection.Count];
            userNamesCollection.CopyTo(usersInRole, 0);
            return usersInRole;
        }

        #endregion

        #region IsUserInRole

        /// <summary>
        /// Determines whether [is user in role] [the specified user name].
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="roleName">Name of the role.</param>
        /// <returns>
        /// 	<c>true</c> if [is user in role] [the specified user name]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsUserInRole(string userName, string roleName)
        {
            XPSecurityUser securityUser = (XPSecurityUser) securityUserProvider.GetUser(userName, false);
            if (securityUser != null)
            {
                GroupOperator criteria = new GroupOperator();
                criteria.Operands.Add(new BinaryOperator("Name", roleName, BinaryOperatorType.Equal));
                criteria.Operands.Add(new ContainsOperator("Users", new BinaryOperator("This", securityUser)));

                XPCollection<XPSecurityRole> securityRoles =
                    new XPCollection<XPSecurityRole>(criteria);
                return securityRoles.Count > 0;
            }

            return false;
        }

        #endregion

        #region Clear

        /// <summary>
        /// Clears this instance.
        /// </summary>
        public void Clear()
        {
            XPCollection<XPSecurityRole> xpCollection = new XPCollection<XPSecurityRole>();
            xpCollection.Session.Delete(xpCollection);
        }

        #endregion
    }
}